package com.dctp.ems.interceptor;

import com.dctp.ems.config.OpsLog;
import com.dctp.ems.utils.OpsLogUtil;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * OpsLogInterceptor（最终整合版）
 *
 * 使用方式（示例）：
 * @Before({Tx.class, OpsLogInterceptor.class})
 * @OpsLog(module = "用户管理", action = "更新用户", table = "dctp_user", remark = "修改用户 ${id}: ${changes}")
 * public void update() { Record body = jsonBody(); ... }
 *
 * 说明：
 * - 拦截器会优先尝试调用 controller.jsonBody()（反射），获取 newRec（Record）。
 * - 读取 id（优先 getParaToLong(0)，其次 request param "id"，最后 newRec.get("id")）。
 * - 若 table 与 id 可用，会自动读取 oldRec = Db.findById(table, id) 并调用
 *   OpsLogUtil.saveChangesAndSave(adminId, username, module, action, table, oldRec, newRec)
 * - 否则会调用 OpsLogUtil.save(...) 写一条简短日志（执行 action）。
 */
public class OpsLogInterceptor implements Interceptor {

    @Override
    public void intercept(Invocation inv) {
        boolean success = true;
        Exception ex = null;
        try {
            inv.invoke();
        } catch (Exception e) {
            success = false;
            ex = e;
            throw e;
        } finally {
            try {
                handleLog(inv, success, ex);
            } catch (Exception e) {
                // 日志失败不应影响业务
                e.printStackTrace();
            }
        }
    }

    private void handleLog(Invocation inv, boolean success, Exception ex) {
        Method method = inv.getMethod();
        OpsLog ops = method.getAnnotation(OpsLog.class);
        if (ops == null) {
            return; // 仅处理标注了 @OpsLog 的方法
        }

        // 1. 读取 newRec（优先 controller.jsonBody()）
        Record newRec = inv.getController().getAttr("jsonBody");
        // 若没有 jsonBody，则尝试从 request parameters 构造（OpsLogUtil 也能处理）
        if (newRec == null) {
            newRec = requestParamsToRecord(inv.getController().getRequest());
        }


        // 4. 获取当前操作用户信息（根据你项目实际改造）
        Long adminId = 0L;
        String username = "unknown";
        try {
            Record userObj = inv.getController().getAttr("reqUser");
            if (userObj != null) {
                try {
                    adminId = userObj.getLong("id");
                } catch (Exception ignored) { }
                try {
                    username =  userObj.getStr("real_name");
                } catch (Exception ignored) { }
            }
        } catch (Exception ignored) { }


        String module = ops.module();
        String action = ops.action();
        String[] limitFields = ops.fields();
        if (null == limitFields || limitFields.length == 0) {
            //新增
            String label = ops.addLabel();
            if (ops.table().equals("dctp_dictionary")) {
                label = newRec.getStr(label);
            }
            String remark = label + "：" + newRec.getStr(ops.addKey());
            OpsLogUtil.save(adminId,username,module,action,remark,null);
            return;
        }

        Set<String> allowedFields = new HashSet<>(Arrays.asList(limitFields));
        Record oldRecord = inv.getController().getAttr("oldRecord");
        if (oldRecord == null) {
            //没成功
            return;
        }
        String table = ops.table() == null ? "" : ops.table().trim();
        OpsLogUtil.saveChangesAndSave(allowedFields,adminId, username, module, action, table, oldRecord, newRec);
    }

    // ---------- 辅助方法 ----------

    // 通过反射尝试从 Controller 读取 jsonBody() 或 getAttr("jsonBody")
    private Record tryGetJsonBodyFromController(Invocation inv) {
        try {
            Object controller = inv.getController();
            // 1) 优先 getAttr("jsonBody")
            try {
                Method getAttr = controller.getClass().getMethod("getAttr", String.class);
                Object attr = getAttr.invoke(controller, "jsonBody");
                if (attr instanceof Record) return (Record) attr;
            } catch (NoSuchMethodException ignored) { }

            // 2) 再尝试 jsonBody()
            try {
                Method jsonBodyMethod = controller.getClass().getMethod("jsonBody");
                Object res = jsonBodyMethod.invoke(controller);
                if (res instanceof Record) return (Record) res;
            } catch (NoSuchMethodException ignored) { }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // 尝试获取 id：先 controller.getParaToLong(0)，再 request param "id"，再 newRec.get("id")
    private Long tryGetId(Invocation inv, Record newRec) {
        Long id = null;
        try {
            Object controller = inv.getController();
            try {
                Method getParaToLong = controller.getClass().getMethod("getParaToLong", int.class);
                Object val = getParaToLong.invoke(controller, 0);
                if (val instanceof Number) id = ((Number) val).longValue();
            } catch (NoSuchMethodException ignored) { }

            if (id == null) {
                String idStr = inv.getController().getRequest().getParameter("id");
                if (idStr != null && !idStr.isEmpty()) {
                    try { id = Long.parseLong(idStr); } catch (NumberFormatException ignored) { }
                }
            }

            if (id == null && newRec != null) {
                Object idv = newRec.get("id");
                if (idv instanceof Number) id = ((Number) idv).longValue();
                else if (idv instanceof String) {
                    try { id = Long.parseLong((String) idv); } catch (NumberFormatException ignored) { }
                }
            }
        } catch (Exception ignored) { }
        return id;
    }

    // 将 request parameters 转为 Record（仅平铺参数）
    private Record requestParamsToRecord(HttpServletRequest request) {
        Record r = new Record();
        try {
            java.util.Enumeration<String> names = request.getParameterNames();
            while (names.hasMoreElements()) {
                String n = names.nextElement();
                r.set(n, request.getParameter(n));
            }
        } catch (Exception ignored) { }
        return r;
    }

    // 用 request 参数替换模板 ${param}
    private String replaceParamsInTemplate(String template, HttpServletRequest request) {
        if (template == null) return "";
        String result = template;
        try {
            java.util.Enumeration<String> names = request.getParameterNames();
            while (names.hasMoreElements()) {
                String n = names.nextElement();
                String placeholder = "${" + n + "}";
                if (result.contains(placeholder)) {
                    String v = request.getParameter(n);
                    result = result.replace(placeholder, v == null ? "" : v);
                }
            }
        } catch (Exception ignored) { }
        return result;
    }
}
